<template>
  <div style="width: 100%; height: 100%">
    <div ref="terminal" style="width: 100%; height: 100%" class="terminal"></div>
  </div>
</template>
<script setup lang="ts">
import { defineProps, ref, defineEmits } from 'vue'
const props = defineProps({ id: { type: String, required: true } })
import { onMounted, onUnmounted } from 'vue'
import 'xterm/css/xterm.css'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
const BASIC_URL = import.meta.env.VITE_API_PATH
const status = ref(null)
let ws = null
let term = null
const terminal = ref(null)
const emit = defineEmits(['statusChange'])
const openTerminal = (id) => {
  term = new Terminal({
    rendererType: 'canvas', //渲染类型
    convertEol: true, //启用时，光标将设置为下一行的开头
    disableStdin: false, //是否应禁用输入。
    cursorStyle: 'underline', //光标样式
    cursorBlink: true, //光标闪烁
    theme: {
      foreground: '#F8F8F8',
      background: '#2D2E2C',
      cursor: 'help', //设置光标
      lineHeight: 16
    },
    fontFamily: '"Cascadia Code", Menlo, monospace'
  })

  let command = ''
  const fitAddon = new FitAddon()
  term.loadAddon(fitAddon)
  term.open(terminal.value)
  term.focus()
  term.onData((e) => {
    ws.send(e)
  })
  fitAddon.fit()
  ws = new WebSocket(BASIC_URL.replace('http', 'ws') + '/toolkit/shell/' + props.id)
  ws.onopen = () => {
    status.value = 'connecting'
    emit('statusChange', 'connecting')
  }
  ws.onmessage = (data) => {
    let json = JSON.parse(data.data)
    const cmd = json.cmd
    const value = json.value
    switch (cmd) {
      case 'status':
        status.value = value
        emit('statusChange', status.value)
        break
      default:
        term.write(value)
        break
    }
  }

  ws.onclose = () => {
    status.value = 'closed'
    emit('statusChange', 'closed')
  }

  //监听并处理error事件
  ws.onerror = function (error) {}
}
onMounted(() => {
  openTerminal()
})
onUnmounted(() => {
  status.value = 'closed'
  emit('statusChange', 'closed')
  ws?.close()
  term?.dispose()
})
defineExpose({
  id: props.id
})
</script>
<style scoped>
.terminal:deep(.xterm) {
  height: 100%;
}
</style>
